#pragma once

#include <iostream>
#include <sys/select.h>
#include <string>
#include <functional>
#include<sys/epoll.h>
#include<unistd.h>
#include<fcntl.h>
#include"err.hpp"
#include "Sock.hpp"

using namespace std;

namespace EPoll_sv
{
    static const int defaultport = 8080;
    static const int size = 128;
    static const int defaultvalue = -1;
    static const int defaultnum = 64;
    using func_t =function<string(const string&)>;
    class EpollServer
    {
    public:
        EpollServer(func_t fun,const int port = defaultport) :_num(defaultnum), _port(port), _listensock(defaultvalue), _epfd(defaultvalue),_func(fun)
        {
        }
        void handlerEvent(int evs)
        {
            for(int i=0;i<evs;i++)//直接遍历已经就绪的事件
            {
                uint32_t event=_reves[i].events;
                int sock=_reves[i].data.fd;
                if(event&EPOLLET)
                {
                    Sock::setNonBlock(sock);
                }
                if(sock==_listensock&&(event&EPOLLIN))//当前是将连接拿上应用层的文件描述符
                {
                    string clientip;
                    uint16_t clientport;
                    int fd=Sock::Accpet(_listensock,&clientip,&clientport);
                    if(fd<0)
                    {
                        logMessage(NORMAL,"accpet sock error");
                        continue;
                    }
                    struct epoll_event ev;
                    ev.data.fd=fd;
                    ev.events=EPOLLIN|EPOLLET;
                    epoll_ctl(_epfd,EPOLL_CTL_ADD,fd,&ev);
                }else if(event&EPOLLIN)//当前是通信的事件
                {
                    char buffer[1024];
                    int n=recv(sock,buffer,sizeof(buffer)-1,0);
                    if(n>0)
                    {
                        buffer[n]=0;
                        cout<<"client# "<<buffer<<endl;
                        string resp=_func(buffer);
                        send(sock,resp.c_str(),resp.size(),0);//将数据发送回去给客户端
                    }else if(n==0)
                    {
                        epoll_ctl(_epfd,EPOLL_CTL_DEL,sock,nullptr);//将sock从epoll中的结构中移除
                        close(sock);//关闭sock
                        logMessage(NORMAL,"client quit");
                    }else
                    {
                        epoll_ctl(_epfd,EPOLL_CTL_DEL,sock,nullptr);//将sock从epoll中的结构中移除
                        close(sock);//关闭sock
                        logMessage(ERROR,"communicate error");
                    }
                }else{}
            }
      //      logMessage(DEBUG,"handlerEvent out");
        }
        void initServer()
        {
            // 获取套接字
            _listensock = Sock::Socket();
            cout << "Sock success" << endl;
            // 绑定网络信息
            Sock::Bind(_listensock, _port);
            cout << "Bind success" << endl;
            // 把套接字设置为监听状态
            Sock::Listen(_listensock);
            cout << "Listen success" << endl;

            _epfd=epoll_create(size);//调用成功返回一个epoll文件描述符，size表示是需要监听的文件描述符的数量
            if(_epfd<0)
            {
                logMessage(FATAL,"epoll_create error");
                exit(EPOLL_CREATE_ERR);
            }
            //将listensock添加到epoll模型中
            struct epoll_event epev;
            epev.events=EPOLLIN|EPOLLET;
            epev.data.fd=_listensock;
            epoll_ctl(_epfd,EPOLL_CTL_ADD,_listensock,&epev);

            //申请就绪时间的空间
            _reves=new struct epoll_event[_num];//申请一块空间，内含_num个事件数
            logMessage(NORMAL, "init server success");
        }


        void start()
        {
            //等待就绪事件
            int timeout=-1;
            for(;;)
            {
                sleep(1);
                logMessage(DEBUG,"epoll_wait ready");
                int re=epoll_wait(_epfd,_reves,_num,timeout);
                logMessage(DEBUG,"epoll_wait end");
                switch (re)
                {
                case 0://0个事件就绪，即超时重传
                logMessage(NORMAL,"timeout...");
                    break;
                case -1://epoll_wait函数调用失败
                logMessage(ERROR,"epoll_wait error,code: %d,errstring: %s",errno,strerror(errno));    
                default://到这里时返回值都大于0，即re为已经就绪的事件数
                logMessage(NORMAL,"wait incident success");
               // handlerEvent(re);
                    break;
                }
            }
        }
        ~EpollServer()
        {
            if(_listensock!=defaultvalue)
            {
                close(_listensock);
            }
            if(_epfd!=defaultvalue)
            {
                close(_epfd);
            }
            if(_reves!=nullptr)
            {
                delete[]_reves;
            }
        }
    private:
        int _port;
        int _listensock;
        int _epfd;
        struct epoll_event* _reves;
        int _num;//事件数
        func_t _func;//外部传递进来的函数
    };
}

static void setNonBlock(int fd)//把文件描述符设置为非阻塞
{
    int n=fcntl(fd,F_GETFL);//获取文件描述符的状态，正常返回非-1的标志位，出错返回-1
    if(n<0)
    {
        cerr<<"fcntl :"<<strerror(errno)<<endl;
       return ;
    }
    fcntl(fd,F_SETFL,n|O_NONBLOCK);//对文件描述符的状态进行设置，设置为非阻塞状态
}